package com.ikingtech.framework.sdk.utils;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import jakarta.servlet.http.HttpServletRequest;
import lombok.*;
import lombok.extern.slf4j.Slf4j;
import nl.basjes.parse.useragent.UserAgent;
import nl.basjes.parse.useragent.UserAgentAnalyzer;
import okhttp3.*;
import okhttp3.internal.sse.RealEventSource;
import okhttp3.sse.EventSource;
import okhttp3.sse.EventSourceListener;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.tools.generic.DateTool;
import org.apache.velocity.tools.generic.MathTool;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.lionsoul.ip2region.xdb.Searcher;
import org.springframework.cglib.beans.BeanCopier;
import org.springframework.cglib.beans.BeanMap;
import org.springframework.cglib.core.Converter;
import org.springframework.scheduling.support.CronExpression;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;

import javax.crypto.Cipher;
import javax.crypto.Mac;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.function.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * The type Tools.
 *
 * @author tie yan
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class Tools {

    /**
     * 字符串处理
     */
    @NoArgsConstructor(access = AccessLevel.PRIVATE)
    public static class Str {

        /**
         * The constant EMPTY.
         */
        public static final String EMPTY = "";

        /**
         * The constant COMMA.
         */
        public static final String COMMA = ",";

        /**
         * The constant COLON.
         */
        public static final String COLON = ":";

        /**
         * The constant SLASH.
         */
        public static final String SLASH = "/";

        /**
         * The constant DEFAULT_PLACEHOLDER.
         */
        public static final String DEFAULT_PLACEHOLDER = "{}";

        /**
         * The constant CONTENT_PLACEHOLDER_PREFIX.
         */
        public static final String CONTENT_PLACEHOLDER_PREFIX = "${";

        /**
         * The constant CONTENT_PLACEHOLDER_SUFFIX.
         */
        public static final String CONTENT_PLACEHOLDER_SUFFIX = "}";

        /**
         * Equals boolean.
         *
         * @param str1 the str 1
         * @param str2 the str 2
         * @return the boolean
         */
        public static boolean equals(String str1, String str2) {
            if (null == str1) {
                return str2 == null;
            } else if (null == str2) {
                return false;
            } else {
                return str1.equalsIgnoreCase(str2);
            }
        }

        /**
         * Is blank boolean.
         *
         * @param str the str
         * @return the boolean
         */
        public static boolean isBlank(String str) {
            if (str == null || str.isEmpty()) {
                return true;
            } else {
                for (int i = 0; i < str.length(); i++) {
                    if (!Character.isWhitespace(str.charAt(i))) {
                        return false;
                    }
                }
            }
            return true;
        }

        /**
         * Is not blank boolean.
         *
         * @param str the str
         * @return the boolean
         */
        public static boolean isNotBlank(String str) {
            if (str == null || str.isEmpty()) {
                return false;
            } else {
                for (int i = 0; i < str.length(); i++) {
                    if (!Character.isWhitespace(str.charAt(i))) {
                        return true;
                    }
                }
            }
            return false;
        }

        /**
         * Is string.
         *
         * @param origin the origin
         * @return the string
         */
        public static String is(String origin) {
            return isBlank(origin) ? EMPTY : origin;
        }

        /**
         * Is string.
         *
         * @param origin     the origin
         * @param defaultStr the default str
         * @return the string
         */
        public static String is(String origin, String defaultStr) {
            return isBlank(origin) ? defaultStr : origin;
        }

        /**
         * Replace string.
         *
         * @param str               the str
         * @param placeHolderPrefix the place holder prefix
         * @param placeHolderSuffix the place holder suffix
         * @param fillStrMap        the fill str map
         * @return the string
         */
        public static String replace(String str, String placeHolderPrefix, String placeHolderSuffix, Map<String, Object> fillStrMap) {
            if (isBlank(str)) {
                return str;
            }
            if (!str.contains(placeHolderPrefix) || !str.contains(placeHolderSuffix)) {
                return str;
            }
            do {
                String param = str.substring(str.indexOf(placeHolderPrefix) + placeHolderPrefix.length(), str.indexOf(placeHolderSuffix));
                str = str.replace(placeHolderPrefix + param + placeHolderSuffix,
                        fillStrMap.containsKey(param) && null != fillStrMap.get(param) ?
                                (CharSequence) fillStrMap.get(param) : Str.EMPTY);
            } while (str.contains(placeHolderPrefix));
            return str;
        }

        /**
         * Format string.
         *
         * @param template the template
         * @param params   the params
         * @return the string
         */
        public static String format(String template, List<String> params) {
            if (null == template || template.isEmpty()) {
                return "";
            }
            if (!template.contains(DEFAULT_PLACEHOLDER)) {
                return template;
            }

            StringBuilder builder = new StringBuilder(template.length() + 16 * params.size());
            int templateStart = 0;
            int i = 0;
            while (i < params.size()) {
                int placeholderStart = template.indexOf(DEFAULT_PLACEHOLDER, templateStart);
                if (placeholderStart == -1) {
                    break;
                }
                builder.append(template, templateStart, placeholderStart);
                builder.append(params.get(i++));
                templateStart = placeholderStart + 2;
            }
            builder.append(template, templateStart, template.length());

            return builder.toString();
        }

        /**
         * Format string.
         *
         * @param template the template
         * @param params   the params
         * @return the string
         */
        public static String format(String template, Object... params) {
            if (null == template || template.isEmpty()) {
                return "";
            }
            if (!template.contains(DEFAULT_PLACEHOLDER)) {
                return template;
            }

            StringBuilder builder = new StringBuilder(template.length() + 16 * params.length);
            int templateStart = 0;
            int i = 0;
            while (i < params.length) {
                int placeholderStart = template.indexOf(DEFAULT_PLACEHOLDER, templateStart);
                if (placeholderStart == -1) {
                    break;
                }
                builder.append(template, templateStart, placeholderStart);
                builder.append(params[i++]);
                templateStart = placeholderStart + 2;
            }
            builder.append(template, templateStart, template.length());

            return builder.toString();
        }

        /**
         * Split list.
         *
         * @param str the str
         * @return the list
         */
        public static List<String> split(String str) {
            return split(str, ",");
        }

        /**
         * Split list.
         *
         * @param str       the str
         * @param separator the separator
         * @return the list
         */
        public static List<String> split(String str, String separator) {
            if (isBlank(str)) {
                return new ArrayList<>();
            }
            return Splitter.on(separator).splitToList(str);
        }

        /**
         * Join string.
         *
         * @param str1      the str 1
         * @param str2      the str 2
         * @param separator the separator
         * @return the string
         */
        public static String join(String str1, String str2, String separator) {
            return Joiner.on(separator).join(str1, str2);
        }

        /**
         * Join string.
         *
         * @param str       the str
         * @param separator the separator
         * @return the string
         */
        public static String join(List<String> str, String separator) {
            return Joiner.on(separator).join(str);
        }

        /**
         * Remove prefix string.
         *
         * @param str    the str
         * @param prefix the prefix
         * @return the string
         */
        public static String removePrefix(String str, String prefix) {
            if (Str.isBlank(str) || Str.isBlank(prefix)) {
                return str;
            }
            if (str.startsWith(prefix)) {
                return str.substring(prefix.length());
            }
            return str;
        }

        /**
         * Remove prefix string.
         *
         * @param str      the str
         * @param prefixes the prefixes
         * @return the string
         */
        public static String removePrefix(String str, String... prefixes) {
            String originStr = str;
            for (String prefix : prefixes) {
                str = removePrefix(str, prefix);
                if (!equals(originStr, str)) {
                    return str;
                }
            }
            return str;
        }

        /**
         * Remove suffix string.
         *
         * @param str    the str
         * @param suffix the suffix
         * @return the string
         */
        public static String removeSuffix(String str, String suffix) {
            if (Str.isBlank(str) || Str.isBlank(suffix)) {
                return str;
            }
            if (str.endsWith(suffix)) {
                return str.substring(0, str.length() - suffix.length());
            }
            return str;
        }

        /**
         * Lower first string.
         *
         * @param str the str
         * @return the string
         */
        public static String lowerFirst(CharSequence str) {
            if (null == str) {
                return null;
            }
            if (!str.isEmpty()) {
                char firstChar = str.charAt(0);
                if (Character.isUpperCase(firstChar)) {
                    return Character.toLowerCase(firstChar) + subSuf(str, 1);
                }
            }
            return str.toString();
        }

        /**
         * Sub suf string.
         *
         * @param string    the string
         * @param fromIndex the from index
         * @return the string
         */
        public static String subSuf(CharSequence string, int fromIndex) {
            if (isEmpty(string)) {
                return null;
            }
            return sub(string, fromIndex, string.length());
        }

        /**
         * Is empty boolean.
         *
         * @param str the str
         * @return the boolean
         */
        public static boolean isEmpty(CharSequence str) {
            return str == null || str.isEmpty();
        }

        /**
         * Sub string.
         *
         * @param str              the str
         * @param fromIndexInclude the from index include
         * @param toIndexExclude   the to index exclude
         * @return the string
         */
        public static String sub(CharSequence str, int fromIndexInclude, int toIndexExclude) {
            if (isEmpty(str)) {
                return str(str);
            }
            int len = str.length();

            if (fromIndexInclude < 0) {
                fromIndexInclude = len + fromIndexInclude;
                if (fromIndexInclude < 0) {
                    fromIndexInclude = 0;
                }
            } else if (fromIndexInclude > len) {
                fromIndexInclude = len;
            }

            if (toIndexExclude < 0) {
                toIndexExclude = len + toIndexExclude;
                if (toIndexExclude < 0) {
                    toIndexExclude = len;
                }
            } else if (toIndexExclude > len) {
                toIndexExclude = len;
            }

            if (toIndexExclude < fromIndexInclude) {
                int tmp = fromIndexInclude;
                fromIndexInclude = toIndexExclude;
                toIndexExclude = tmp;
            }

            if (fromIndexInclude == toIndexExclude) {
                return EMPTY;
            }

            return str.toString().substring(fromIndexInclude, toIndexExclude);
        }

        /**
         * Str string.
         *
         * @param cs the cs
         * @return the string
         */
        public static String str(CharSequence cs) {
            return null == cs ? null : cs.toString();
        }

        /**
         * To snake case string.
         *
         * @param str the str
         * @return the string
         */
        public static String toSnakeCase(String str) {
            return toSeparate(str, "_");
        }

        /**
         * To hyphen separate string.
         *
         * @param str the str
         * @return the string
         */
        public static String toHyphenSeparate(String str) {
            return toSeparate(str, "-");
        }

        /**
         * To dot separate string.
         *
         * @param str the str
         * @return the string
         */
        public static String toDotSeparate(String str) {
            return toSeparate(str, ".");
        }

        /**
         * To separate string.
         *
         * @param str    the str
         * @param symbol the symbol
         * @return the string
         */
        public static String toSeparate(String str, String symbol) {
            if (isBlank(str)) {
                return EMPTY;
            }
            final StringBuilder sb = new StringBuilder(str.length());
            for (int i = 0; i < str.length(); i++) {
                char c = str.charAt(i);
                if (Character.isUpperCase(c)) {
                    sb.append(symbol).append(Character.toLowerCase(c));
                } else {
                    sb.append(c);
                }
            }
            return sb.toString();
        }

        /**
         * To upper camel case without separate string.
         *
         * @param str the str
         * @return the string
         */
        public static String toUpperCamelCaseWithoutSeparate(String str) {
            if (isBlank(str)) {
                return EMPTY;
            }
            final StringBuilder sb = new StringBuilder(str.length());
            for (int i = 0; i < str.length(); i++) {
                char c = str.charAt(i);
                if (i == 0) {
                    sb.append(Character.toUpperCase(c));
                } else {
                    sb.append(c);
                }
            }
            return sb.toString();
        }

        /**
         * To upper camel case string.
         *
         * @param str the str
         * @return the string
         */
        public static String toUpperCamelCase(String str) {
            return toUpperCamelCase(str, '_');
        }

        /**
         * To upper camel case string.
         *
         * @param str    the str
         * @param symbol the symbol
         * @return the string
         */
        public static String toUpperCamelCase(String str, char symbol) {
            return toCamelCase(str, symbol, true);
        }

        /**
         * To lower camel case string.
         *
         * @param str the str
         * @return the string
         */
        public static String toLowerCamelCase(String str) {
            return toLowerCamelCase(str, '_');
        }

        /**
         * To lower camel case string.
         *
         * @param str    the str
         * @param symbol the symbol
         * @return the string
         */
        public static String toLowerCamelCase(String str, char symbol) {
            return toCamelCase(str, symbol, false);
        }

        /**
         * To camel case string.
         *
         * @param str        the str
         * @param symbol     the symbol
         * @param upperFirst the upper first
         * @return the string
         */
        public static String toCamelCase(String str, char symbol, Boolean upperFirst) {
            if (isBlank(str)) {
                return EMPTY;
            }
            if (str.indexOf(symbol) > -1) {
                final StringBuilder sb = new StringBuilder(str.length());
                boolean upperCase = false;
                for (int i = 0; i < str.length(); i++) {
                    char c = str.charAt(i);
                    if (i == 0 && Boolean.TRUE.equals(upperFirst)) {
                        sb.append(Character.toUpperCase(c));
                    } else if (c == symbol) {
                        upperCase = true;
                    } else if (upperCase) {
                        sb.append(Character.toUpperCase(c));
                        upperCase = false;
                    } else {
                        sb.append(Character.toLowerCase(c));
                    }
                }
                return sb.toString();
            } else {
                return str;
            }
        }

        /**
         * To lower camel case without separate string.
         *
         * @param str the str
         * @return the string
         */
        public static String toLowerCamelCaseWithoutSeparate(String str) {
            if (isBlank(str)) {
                return EMPTY;
            }
            final StringBuilder sb = new StringBuilder(str.length());
            for (int i = 0; i < str.length(); i++) {
                char c = str.charAt(i);
                if (i == 0) {
                    sb.append(Character.toLowerCase(c));
                } else {
                    sb.append(c);
                }
            }
            return sb.toString();
        }

        /**
         * Find placeholder list.
         *
         * @param source            the source
         * @param placeholderPrefix the placeholder prefix
         * @param placeholderSuffix the placeholder suffix
         * @return the list
         */
        public static List<String> findPlaceholder(String source, String placeholderPrefix, String placeholderSuffix) {
            return findPlaceholder(source, placeholderPrefix, placeholderSuffix, s -> s);
        }

        /**
         * Find placeholder list.
         *
         * @param source            the source
         * @param placeholderPrefix the placeholder prefix
         * @param placeholderSuffix the placeholder suffix
         * @param processor         the processor
         * @return the list
         */
        public static List<String> findPlaceholder(String source, String placeholderPrefix, String placeholderSuffix, UnaryOperator<String> processor) {
            List<String> result = new ArrayList<>();

            do {
                result.add(processor.apply(source.substring(source.indexOf(placeholderPrefix) + 2, source.indexOf(placeholderSuffix))));
                source = source.substring(source.indexOf("}}") + 1);
            } while (source.contains("{{"));
            return result;
        }

        public static int compare(String str1, String str2) {
            return 0;
        }
    }

    /**
     * The type Array.
     */
    public static class Array {

        private Array() {

        }

        /**
         * Is blank boolean.
         *
         * @param <T>   the type parameter
         * @param array the array
         * @return the boolean
         */
        public static <T> boolean isBlank(T[] array) {
            return null == array || array.length == 0;
        }

        /**
         * Is not blank boolean.
         *
         * @param <T>   the type parameter
         * @param array the array
         * @return the boolean
         */
        public static <T> boolean isNotBlank(T[] array) {
            return null != array && array.length > 0;
        }


        /**
         * Traverse list.
         *
         * @param <T>       the type parameter
         * @param origin    the origin
         * @param filter    the filter
         * @param traverser the traverser
         * @return the list
         */
        public static <T> List<T> traverse(T[] origin, Predicate<? super T> filter, UnaryOperator<T> traverser) {
            return Coll.traverse(Coll.newList(origin), filter, traverser);
        }

        /**
         * Filter list.
         *
         * @param <T>    the type parameter
         * @param origin the origin
         * @param filter the filter
         * @return the list
         */
        public static <T> List<T> filter(T[] origin, Predicate<? super T> filter) {
            return Coll.filter(Coll.newList(origin), filter);
        }

        /**
         * Convert list list.
         *
         * @param <T>       the type parameter
         * @param <R>       the type parameter
         * @param origin    the origin
         * @param processor the processor
         * @return the list
         */
        public static <T, R> List<R> convertList(T[] origin, Function<T, R> processor) {
            Objects.requireNonNull(processor);
            return isBlank(origin) ? new ArrayList<>() : Arrays.stream(origin).map(processor).filter(Objects::nonNull).toList();
        }

        /**
         * Convert list list.
         *
         * @param <T>       the type parameter
         * @param <R>       the type parameter
         * @param origin    the origin
         * @param filter    the filter
         * @param processor the processor
         * @return the list
         */
        public static <T, R> List<R> convertList(T[] origin, Predicate<? super T> filter, Function<T, R> processor) {
            Objects.requireNonNull(processor);
            return isBlank(origin) ? new ArrayList<>() : Arrays.stream(origin).filter(filter).map(processor).filter(Objects::nonNull).toList();
        }

        /**
         * Convert group map.
         *
         * @param <T>     the type parameter
         * @param <K>     the type parameter
         * @param origin  the origin
         * @param keyFunc the key func
         * @return the map
         */
        public static <T, K> Map<K, List<T>> convertGroup(T[] origin, Function<T, K> keyFunc) {
            Objects.requireNonNull(keyFunc);

            return isBlank(origin) ? new HashMap<>(0) : Arrays.stream(origin).collect(Collectors.groupingBy(keyFunc));
        }
    }

    public static class Coll {

        private Coll() {

        }

        @SafeVarargs
        public static <T> List<T> merge(List<T>... collections) {
            if (collections.length == 0) {
                return Collections.emptyList();
            }
            List<T> result = new ArrayList<>();
            for (List<T> collection : collections) {
                if (isBlank(collection)) {
                    continue;
                }
                result.addAll(collection);
            }
            return result;
        }

        @SafeVarargs
        public static <T> List<T> merge(T item, List<T>... collections) {
            List<T> result = merge(collections);
            if (null != item) {
                result.add(item);
            }
            return result;
        }

        public static <T> List<T> filter(Collection<T> origin, Predicate<? super T> filter) {
            return isBlank(origin) ? new ArrayList<>() : origin.stream().filter(filter).distinct().collect(Collectors.toList());
        }

        public static <T> List<T> traverse(List<T> origin, UnaryOperator<T> traverser) {
            return traverse(origin, t -> true, traverser);
        }

        public static <T> List<T> traverse(List<T> origin, Predicate<? super T> filter, UnaryOperator<T> traverser) {
            Objects.requireNonNull(traverser);

            if (Coll.isBlank(origin)) {
                return new ArrayList<>();
            }

            List<T> result = new ArrayList<>();
            origin.stream().filter(filter).distinct().forEach(o -> {
                T apply = traverser.apply(o);
                if (null != apply) {
                    result.add(apply);
                }
            });

            return result;
        }

        public static <T> List<T> distinct(Collection<T> origin) {
            return Coll.isBlank(origin) ? new ArrayList<>() : origin.stream().distinct().collect(Collectors.toList());
        }

        public static <T, R> List<R> convertList(Collection<T> origin, Function<T, R> processor) {
            Objects.requireNonNull(processor);

            return Coll.isBlank(origin) ? new ArrayList<>() : origin.stream().map(processor).filter(Objects::nonNull).distinct().collect(Collectors.toList());
        }

        public static <T, R, U extends Comparable<? super U>> List<R> convertListWithSort(List<T> origin, Function<T, R> processor, Function<? super R, ? extends U> comparatorField) {
            Objects.requireNonNull(processor);

            return Coll.isBlank(origin) ? new ArrayList<>() : origin.stream().map(processor).filter(Objects::nonNull).sorted(Comparator.comparing(comparatorField)).collect(Collectors.toList());
        }

        public static <T, R, U extends Comparable<? super U>> List<R> convertListWithSortDesc(List<T> origin, Function<T, R> processor, Function<? super R, ? extends U> comparatorField) {
            Objects.requireNonNull(processor);

            return Coll.isBlank(origin) ? new ArrayList<>() : origin.stream().map(processor).filter(Objects::nonNull).sorted(Comparator.comparing(comparatorField).reversed()).collect(Collectors.toList());
        }

        public static <T, R, U extends Comparable<? super U>> List<R> convertListWithSort(List<T> origin, Predicate<? super T> filter, Function<T, R> processor, Function<? super R, ? extends U> comparatorField) {
            Objects.requireNonNull(processor);

            return Coll.isBlank(origin) ? new ArrayList<>() : origin.stream().filter(filter).map(processor).filter(Objects::nonNull).sorted(Comparator.comparing(comparatorField)).collect(Collectors.toList());
        }

        /**
         * Convert list list.
         *
         * @param <T>       the type parameter
         * @param <R>       the type parameter
         * @param origin    the origin
         * @param filter    the filter
         * @param processor the processor
         * @return the list
         */
        public static <T, R> List<R> convertList(List<T> origin, Predicate<? super T> filter, Function<T, R> processor) {
            Objects.requireNonNull(processor);

            return isBlank(origin) ? new ArrayList<>() : origin.stream().filter(filter).map(processor).filter(Objects::nonNull).distinct().collect(Collectors.toList());
        }

        /**
         * Map filter map.
         *
         * @param <K>    the type parameter
         * @param <V>    the type parameter
         * @param origin the origin
         * @param filter the filter
         * @return the map
         */
        public static <K, V> Map<K, V> mapFilter(Map<K, V> origin, Predicate<? super Map.Entry<K, V>> filter) {
            return isBlankMap(origin) ? new HashMap<>() : origin.entrySet().stream().filter(filter).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
        }

        /**
         * Flat map list.
         *
         * @param <T>       the type parameter
         * @param <K>       the type parameter
         * @param <R>       the type parameter
         * @param origin    the origin
         * @param processor the processor
         * @param mapper    the mapper
         * @return the list
         */
        public static <T, K, R> List<R> flatMap(Collection<T> origin, Function<T, K> processor, Function<? super K, ? extends Stream<? extends R>> mapper) {
            Objects.requireNonNull(processor);
            Objects.requireNonNull(mapper);

            return isBlank(origin) ? new ArrayList<>() : origin.stream().map(processor).flatMap(mapper).collect(Collectors.toList());
        }

        /**
         * Flat map list.
         *
         * @param <T>    the type parameter
         * @param <R>    the type parameter
         * @param origin the origin
         * @param mapper the mapper
         * @return the list
         */
        public static <T, R> List<R> flatMap(Collection<T> origin, Function<? super T, ? extends Stream<? extends R>> mapper) {
            Objects.requireNonNull(mapper);

            return isBlank(origin) ? new ArrayList<>() : origin.stream().flatMap(mapper).collect(Collectors.toList());
        }

        /**
         * Flat map list.
         *
         * @param <T>    the type parameter
         * @param origin the origin
         * @return the list
         */
        public static <T> List<T> flatMap(Collection<Collection<T>> origin) {
            return isBlank(origin) ? new ArrayList<>() : origin.stream().flatMap(Collection::stream).collect(Collectors.toList());
        }

        /**
         * Convert map map.
         *
         * @param <T>       the type parameter
         * @param <K>       the type parameter
         * @param <V>       the type parameter
         * @param origin    the origin
         * @param keyFunc   the key func
         * @param valueFunc the value func
         * @return the map
         */
        public static <T, K, V> Map<K, V> convertMap(List<T> origin, Function<T, K> keyFunc, Function<T, V> valueFunc) {
            Objects.requireNonNull(keyFunc);
            Objects.requireNonNull(valueFunc);

            return isBlank(origin) ? new HashMap<>(0) : origin.stream().collect(Collectors.toMap(keyFunc, valueFunc));
        }

        /**
         * Convert map map.
         *
         * @param <T>     the type parameter
         * @param <K>     the type parameter
         * @param origin  the origin
         * @param keyFunc the key func
         * @return the map
         */
        public static <T, K> Map<K, T> convertMap(List<T> origin, Function<T, K> keyFunc) {
            Objects.requireNonNull(keyFunc);

            return isBlank(origin) ? new HashMap<>(0) : origin.stream().collect(Collectors.toMap(keyFunc, o -> o));
        }

        /**
         * Convert map map.
         *
         * @param <T>       the type parameter
         * @param <K>       the type parameter
         * @param <V>       the type parameter
         * @param origin    the origin
         * @param filter    the filter
         * @param keyFunc   the key func
         * @param valueFunc the value func
         * @return the map
         */
        public static <T, K, V> Map<K, V> convertMap(List<T> origin, Predicate<? super T> filter, Function<T, K> keyFunc, Function<T, V> valueFunc) {
            Objects.requireNonNull(keyFunc);
            Objects.requireNonNull(valueFunc);

            return isBlank(origin) ? new HashMap<>(0) : origin.stream().filter(filter).collect(Collectors.toMap(keyFunc, valueFunc));
        }

        /**
         * Convert group map.
         *
         * @param <T>         the type parameter
         * @param <K>         the type parameter
         * @param <V>         the type parameter
         * @param origin      the origin
         * @param keyFunc     the key func
         * @param mappingFunc the mapping func
         * @return the map
         */
        public static <T, K, V> Map<K, List<V>> convertGroup(List<T> origin, Function<T, K> keyFunc, Function<T, V> mappingFunc) {
            Objects.requireNonNull(keyFunc);
            Objects.requireNonNull(mappingFunc);

            return isBlank(origin) ? new HashMap<>(0) : origin.stream().collect(Collectors.groupingBy(keyFunc, Collectors.mapping(mappingFunc, Collectors.toList())));
        }

        /**
         * Convert group map.
         *
         * @param <T>     the type parameter
         * @param <K>     the type parameter
         * @param origin  the origin
         * @param keyFunc the key func
         * @return the map
         */
        public static <T, K> Map<K, List<T>> convertGroup(List<T> origin, Function<T, K> keyFunc) {
            Objects.requireNonNull(keyFunc);

            return isBlank(origin) ? new HashMap<>(0) : origin.stream().collect(Collectors.groupingBy(keyFunc));
        }

        /**
         * Convert group with filter map.
         *
         * @param <T>     the type parameter
         * @param <K>     the type parameter
         * @param origin  the origin
         * @param filter  the filter
         * @param keyFunc the key func
         * @return the map
         */
        public static <T, K> Map<K, List<T>> convertGroupWithFilter(List<T> origin, Predicate<? super T> filter, Function<T, K> keyFunc) {
            Objects.requireNonNull(keyFunc);

            return isBlank(origin) ? new HashMap<>(0) : origin.stream().filter(filter).collect(Collectors.groupingBy(keyFunc));
        }

        /**
         * Convert group with filter map.
         *
         * @param <T>         the type parameter
         * @param <K>         the type parameter
         * @param <V>         the type parameter
         * @param origin      the origin
         * @param filter      the filter
         * @param keyFunc     the key func
         * @param mappingFunc the mapping func
         * @return the map
         */
        public static <T, K, V> Map<K, List<V>> convertGroupWithFilter(List<T> origin, Predicate<? super T> filter, Function<T, K> keyFunc, Function<T, V> mappingFunc) {
            Objects.requireNonNull(keyFunc);

            return isBlank(origin) ? new HashMap<>(0) : origin.stream().filter(filter).collect(Collectors.groupingBy(keyFunc, Collectors.mapping(mappingFunc, Collectors.toList())));
        }

        /**
         * Convert group with double sum map.
         *
         * @param <T>          the type parameter
         * @param <K>          the type parameter
         * @param origin       the origin
         * @param keyFunc      the key func
         * @param sumValueFunc the sum value func
         * @return the map
         */
        public static <T, K> Map<K, Double> convertGroupWithDoubleSum(List<T> origin, Function<T, K> keyFunc, ToDoubleFunction<T> sumValueFunc) {
            Objects.requireNonNull(keyFunc);
            Objects.requireNonNull(sumValueFunc);

            return isBlank(origin) ? new HashMap<>(0) : origin.stream().collect(Collectors.groupingBy(keyFunc, Collectors.summingDouble(sumValueFunc)));
        }

        public static <T, R> Map<R, Long> convertGroupAndCount(List<T> origin, Function<T, R> keyFunc) {
            return isBlank(origin) ? new HashMap<>() : origin.stream().collect(Collectors.groupingBy(keyFunc, Collectors.counting()));
        }

        /**
         * Sum integer.
         *
         * @param <T>       the type parameter
         * @param origin    the origin
         * @param processor the processor
         * @return the integer
         */
        public static <T> Integer sum(List<T> origin, ToIntFunction<T> processor) {
            Objects.requireNonNull(processor);

            return isBlank(origin) ? 0 : origin.stream().mapToInt(processor).sum();
        }

        /**
         * Map sum integer.
         *
         * @param <K>    the type parameter
         * @param <V>    the type parameter
         * @param origin the origin
         * @return the integer
         */
        public static <K, V extends Integer> Integer mapSum(Map<K, V> origin) {
            return isBlankMap(origin) ? 0 : origin.values().stream().mapToInt(Integer::intValue).sum();
        }

        /**
         * Long sum long.
         *
         * @param <T>       the type parameter
         * @param origin    the origin
         * @param processor the processor
         * @return the long
         */
        public static <T> Long longSum(List<T> origin, ToLongFunction<T> processor) {
            Objects.requireNonNull(processor);

            return isBlank(origin) ? 0L : origin.stream().mapToLong(processor).sum();
        }

        /**
         * Long sum long.
         *
         * @param <T>       the type parameter
         * @param origin    the origin
         * @param processor the processor
         * @return the long
         */
        public static <T> Double doubleSum(List<T> origin, ToDoubleFunction<T> processor) {
            Objects.requireNonNull(processor);

            return isBlank(origin) ? 0D : origin.stream().mapToDouble(processor).sum();
        }

        /**
         * Big decimal sum big decimal.
         *
         * @param <T>       the type parameter
         * @param origin    the origin
         * @param processor the processor
         * @return the big decimal
         */
        public static <T> BigDecimal bigDecimalSum(List<T> origin, Function<T, BigDecimal> processor) {
            Objects.requireNonNull(processor);

            return isBlank(origin) ? BigDecimal.ZERO : origin.stream().map(processor).reduce(BigDecimal.ZERO, BigDecimal::add);
        }

        /**
         * Sort list.
         *
         * @param <T>          the type parameter
         * @param <U>          the type parameter
         * @param origin       the origin
         * @param compareField the compare field
         * @return the list
         */
        public static <T, U extends Comparable<? super U>> List<T> sort(List<T> origin, Function<? super T, ? extends U> compareField) {
            return isBlank(origin) ? new ArrayList<>() : origin.stream().sorted(Comparator.comparing(compareField)).collect(Collectors.toList());
        }

        /**
         * Sort list.
         *
         * @param <T>    the type parameter
         * @param origin the origin
         * @return the list
         */
        public static <T> List<T> sort(Collection<T> origin) {
            return isBlank(origin) ? new ArrayList<>() : origin.stream().sorted().collect(Collectors.toList());
        }

        /**
         * Sort desc list.
         *
         * @param <T>          the type parameter
         * @param <U>          the type parameter
         * @param origin       the origin
         * @param compareField the compare field
         * @return the list
         */
        public static <T, U extends Comparable<? super U>> List<T> sortDesc(List<T> origin, Function<? super T, ? extends U> compareField) {
            return isBlank(origin) ? new ArrayList<>() : origin.stream().sorted(Comparator.comparing(compareField).reversed()).collect(Collectors.toList());
        }

        /**
         * Contains boolean.
         *
         * @param <T>    the type parameter
         * @param <K>    the type parameter
         * @param origin the origin
         * @param source the source
         * @param target the target
         * @return the boolean
         */
        public static <T, K> boolean contains(List<T> origin, Function<T, K> source, K target) {
            Objects.requireNonNull(source);

            return isNotBlank(origin) && origin.stream().map(source).toList().contains(target);
        }

        /**
         * Contains boolean.
         *
         * @param <T>    the type parameter
         * @param origin the origin
         * @param target the target
         * @return the boolean
         */
        public static <T> boolean contains(List<T> origin, T target) {
            return isNotBlank(origin) && origin.contains(target);
        }

        /**
         * Is all boolean.
         *
         * @param <T>            the type parameter
         * @param <R>            the type parameter
         * @param origin         the origin
         * @param field          the field
         * @param compareToValue the compare to value
         * @return the boolean
         */
        public static <T, R> boolean isAll(List<T> origin, Function<T, R> field, R compareToValue) {
            Objects.requireNonNull(field);

            List<T> incompatible = origin.stream().filter(o -> !field.apply(o).equals(compareToValue)).toList();
            return Coll.isBlank(incompatible);
        }

        /**
         * New map map.
         *
         * @param <K>      the type parameter
         * @param <V>      the type parameter
         * @param elements the elements
         * @return the map
         */
        @SafeVarargs
        public static <K, V> Map<K, V> newMap(Kv<K, V>... elements) {
            Map<K, V> result = new HashMap<>(elements.length);
            for (Kv<K, V> element : elements) {
                result.put(element.getKey(), element.getValue());
            }
            return result;
        }

        /**
         * Intersection list.
         *
         * @param coll1 the coll 1
         * @param coll2 the coll 2
         * @return the list
         */
        public static List<String> intersection(List<String> coll1, List<String> coll2) {
            return intersection(coll1, coll2, false);
        }

        /**
         * Intersection list.
         *
         * @param coll1       the coll 1
         * @param coll2       the coll 2
         * @param ignoreBlank the ignore blank
         * @return the list
         */
        public static List<String> intersection(List<String> coll1, List<String> coll2, Boolean ignoreBlank) {
            if (isBlank(coll1) && isBlank(coll2)) {
                return new ArrayList<>();
            }
            if (isBlank(coll1) && isNotBlank(coll2)) {
                return Boolean.TRUE.equals(ignoreBlank) ? coll2 : new ArrayList<>();
            }
            if (isNotBlank(coll1) && isBlank(coll2)) {
                return Boolean.TRUE.equals(ignoreBlank) ? coll1 : new ArrayList<>();
            }
            return coll1.stream().filter(coll2::contains).toList();
        }

        public static <K, V> MultiValueMap<K, V> convertToMultiValueMap(Map<K, V[]> origin) {
            MultiValueMap<K, V> result = new LinkedMultiValueMap<>();
            origin.forEach((k, v) -> result.put(k, newList(v)));
            return result;
        }

        public static void addAll(List<String> origin, List<String> newList) {
            if (null == origin) {
                origin = new ArrayList<>();
            }
            origin.addAll(newList);
        }

        @Getter
        public static class Kv<K, V> {

            private final K key;

            private final V value;

            private Kv(K key, V value) {
                this.key = key;
                this.value = value;
            }

            /**
             * 构造键值对
             *
             * @param <K>   the type parameter
             * @param <V>   the type parameter
             * @param key   键
             * @param value 值
             * @return 键值对 kv
             */
            public static <K, V> Kv<K, V> of(K key, V value) {
                return new Kv<>(key, value);
            }

            /**
             * Get v.
             *
             * @return the v
             */
            public V get() {
                return this.value;
            }
        }

        /**
         * New list list.
         *
         * @param <T>      the type parameter
         * @param elements the elements
         * @return the list
         */
        @SafeVarargs
        public static <T> List<T> newList(T... elements) {
            return new ArrayList<>(Arrays.asList(elements));
        }

        /**
         * New list list.
         *
         * @param <T>               the type parameter
         * @param elementsSuppliers the elements suppliers
         * @return the list
         */
        @SafeVarargs
        public static <T> List<T> newList(Supplier<T>... elementsSuppliers) {
            List<T> result = new ArrayList<>();
            for (Supplier<T> supplier : elementsSuppliers) {
                result.add(supplier.get());
            }
            return result;
        }

        /**
         * Join string.
         *
         * @param <T>        the type parameter
         * @param collection the collection
         * @param separator  the separator
         * @return the string
         */
        public static <T> String join(Collection<T> collection, String separator) {
            if (Coll.isBlank(collection)) {
                return Str.EMPTY;
            }
            if (collection.size() == 1) {
                return collection.iterator().next().toString();
            }
            Iterator<T> iterator = collection.iterator();
            StringBuilder stringBuilder = new StringBuilder();
            if (iterator.hasNext()) {
                stringBuilder.append(iterator.next());
                while (iterator.hasNext()) {
                    stringBuilder.append(separator).append(iterator.next());
                }
            }
            return stringBuilder.toString();
        }

        /**
         * 将集合中的元素用逗号连接起来,返回String
         *
         * @param <T>        泛型
         * @param collection 集合
         * @return 连接好的字符串 string
         */
        public static <T> String join(Collection<T> collection) {
            return join(collection, ",");
        }

        /**
         * Is blank boolean.
         *
         * @param <T>        the type parameter
         * @param collection the collection
         * @return the boolean
         */
        public static <T> boolean isBlank(Collection<T> collection) {
            return null == collection || collection.isEmpty();
        }

        /**
         * Is not blank boolean.
         *
         * @param <T>        the type parameter
         * @param collection the collection
         * @return the boolean
         */
        public static <T> boolean isNotBlank(Collection<T> collection) {
            return null != collection && !collection.isEmpty();
        }

        /**
         * Is blank map boolean.
         *
         * @param <K> the type parameter
         * @param <V> the type parameter
         * @param map the map
         * @return the boolean
         */
        public static <K, V> boolean isBlankMap(Map<K, V> map) {
            return null == map || map.isEmpty();
        }

        /**
         * Is not blank map boolean.
         *
         * @param <K> the type parameter
         * @param <V> the type parameter
         * @param map the map
         * @return the boolean
         */
        public static <K, V> boolean isNotBlankMap(Map<K, V> map) {
            return null != map && !map.isEmpty();
        }
    }

    /**
     * The type Json.
     */
    @Slf4j
    @NoArgsConstructor(access = AccessLevel.PRIVATE)
    public static class Json {

        private static final ObjectMapper OBJECT_MAPPER = JsonMapper.builder()
                .defaultLocale(Locale.SIMPLIFIED_CHINESE)
                .defaultTimeZone(TimeZone.getTimeZone("Asia/Shanghai"))
                .addModule(new JavaTimeModule())
                .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
                .disable(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES)
                .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS)
                .enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING)
                .build();

        private static final XmlMapper XML_MAPPER = XmlMapper.builder()
                .defaultLocale(Locale.SIMPLIFIED_CHINESE)
                .defaultTimeZone(TimeZone.getTimeZone("Asia/Shanghai"))
                .addModule(new JavaTimeModule())
                .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
                .disable(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES)
                .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS)
                .enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING)
                .build();

        /**
         * To json str string.
         *
         * @param obj the obj
         * @return the string
         */
        public static String toJsonStr(Object obj) {
            if (null == obj) {
                return Str.EMPTY;
            }
            try {
                return OBJECT_MAPPER.writeValueAsString(obj);
            } catch (JsonProcessingException e) {
                return Str.EMPTY;
            }
        }

        /**
         * To xml string.
         *
         * @param obj the obj
         * @return the string
         */
        public static String toXml(Object obj) {
            try {
                return XML_MAPPER.writeValueAsString(obj);
            } catch (JsonProcessingException e) {
                return Str.EMPTY;
            }
        }

        /**
         * Xml to bean t.
         *
         * @param <T>       the type parameter
         * @param resultStr the result str
         * @param clazz     the clazz
         * @return the t
         */
        public static <T> T xmlToBean(String resultStr, Class<T> clazz) {
            try {
                return XML_MAPPER.readValue(resultStr, clazz);
            } catch (JsonProcessingException e) {
                return null;
            }
        }

        /**
         * To bean t.
         *
         * @param <T>     the type parameter
         * @param jsonStr the json str
         * @param clazz   the clazz
         * @return the t
         */
        public static <T> T toBean(String jsonStr, Class<T> clazz) {
            try {
                return OBJECT_MAPPER.readValue(jsonStr, clazz);
            } catch (JsonProcessingException e) {
                return null;
            }
        }

        /**
         * To bean t.
         *
         * @param <T>          the type parameter
         * @param jsonStr      the json str
         * @param valueTypeRef the value type ref
         * @return the t
         */
        public static <T> T toBean(String jsonStr, TypeReference<T> valueTypeRef) {
            try {
                if (Str.isBlank(jsonStr)) {
                    log.info("jsonStr is empty");
                    return null;
                }
                return OBJECT_MAPPER.readValue(jsonStr, valueTypeRef);
            } catch (JsonProcessingException e) {
                log.info("jsonStr convert exception:{}", e.getMessage());
                return null;
            }
        }

        /**
         * Obj to bean t.
         *
         * @param <T>          the type parameter
         * @param obj          the obj
         * @param valueTypeRef the value type ref
         * @return the t
         */
        public static <T> T objToBean(Object obj, TypeReference<T> valueTypeRef) {
            return OBJECT_MAPPER.convertValue(obj, valueTypeRef);
        }

        /**
         * Obj to map map.
         *
         * @param <K> the type parameter
         * @param <V> the type parameter
         * @param obj the obj
         * @return the map
         */
        public static <K, V> Map<K, V> objToMap(Object obj) {
            return OBJECT_MAPPER.convertValue(obj, new TypeReference<>() {
            });
        }

        public static List<Object> objToList(Object obj) {
            return OBJECT_MAPPER.convertValue(obj, new TypeReference<>() {
            });
        }

        /**
         * To map map.
         *
         * @param <K>     the type parameter
         * @param <V>     the type parameter
         * @param jsonStr the json str
         * @return the map
         */
        public static <K, V> Map<K, V> toMap(String jsonStr) {
            try {
                return OBJECT_MAPPER.readValue(jsonStr, new TypeReference<>() {
                });
            } catch (JsonProcessingException e) {
                return new HashMap<>(0);
            }
        }
    }

    /**
     * The type Bean.
     */
    @Slf4j
    @NoArgsConstructor(access = AccessLevel.PRIVATE)
    public static class Bean {
        /**
         * The Bean copiers.
         */
        static final Map<CopierIdentity, BeanCopier> BEAN_COPIERS = new ConcurrentHashMap<>();

        /**
         * Copy r.
         *
         * @param <R>    the type parameter
         * @param source the source
         * @param clazz  the clazz
         * @return the r
         */
        public static <R> R copy(Object source, Class<R> clazz) {
            if (null == source) {
                return null;
            }
            Class<?> sourceClass = source.getClass();
            CopierIdentity copierIdentity = new CopierIdentity(sourceClass, clazz);
            BeanCopier beanCopier = BEAN_COPIERS.computeIfAbsent(copierIdentity, k -> BeanCopier.create(sourceClass, clazz, true));
            try {
                R output = clazz.getDeclaredConstructor().newInstance();
                beanCopier.copy(source, output, new CustomConverter());
                return output;
            } catch (IllegalAccessException | InstantiationException | InvocationTargetException |
                     NoSuchMethodException e) {
                log.error("[BeanCopier]bean copy exception, {}", e.getMessage());
                return null;
            }
        }

        /**
         * Convert to map map.
         *
         * @param <K>    the type parameter
         * @param <V>    the type parameter
         * @param source the source
         * @return the map
         */
        @SuppressWarnings({"unchecked"})
        public static <K, V> Map<K, V> convertToMap(Object source) {
            return BeanMap.create(source);
        }

        @Data
        @AllArgsConstructor
        private static class CopierIdentity {
            private Class<?> sourceClass;
            private Class<?> targetClass;
        }

        /**
         * The type Custom converter.
         */
        public static class CustomConverter implements Converter {

            @Override
            @SuppressWarnings({"unchecked"})
            public Object convert(Object object, Class targetClass, Object o1) {
                if (object instanceof String && targetClass.isEnum()) {
                    try {
                        return Str.isBlank((String) object) ? null : Enum.valueOf(targetClass, (String) object);
                    } catch (Exception e) {
                        return null;
                    }
                }
                if (object instanceof Enum && targetClass.equals(String.class)) {
                    try {
                        return ((Enum<?>) object).name();
                    } catch (Exception e) {
                        return null;
                    }
                }
                if (object instanceof List && targetClass.equals(String.class)) {
                    return Coll.join((List<?>) object);
                }
                if (object instanceof String && targetClass.equals(List.class)) {
                    return Str.split((String) object);
                }
                return object;
            }
        }
    }

    /**
     * The type Http.
     */
    @Slf4j
    @NoArgsConstructor(access = AccessLevel.PRIVATE)
    public static class Http {

        public static final String SCHEMA_HTTP = "http://";

        public static final String QUERY_PARAM_CONNECT = "?";

        public static final String HEADER_AUTHORIZATION = "Authorization";

        public static final String CONTENT_TYPE_JSON = "application/json";

        public static final String CONTENT_TYPE_FORM = "application/x-www-form-urlencoded";

        public static final String CONTENT_TYPE_EVENT_STREAM = "text/event-stream";

        private static final AntPathMatcher ANT_PATH_MATCHER = new AntPathMatcher();

        private static final OkHttpClient CLIENT = new OkHttpClient()
                .newBuilder()
                .connectionPool(new ConnectionPool(200, 30, TimeUnit.MINUTES))
                .build();

        public static boolean pathMatches(String requestUri, List<String> patterns) {
            if (Coll.isNotBlank(patterns)) {
                for (String pattern : patterns) {
                    if (ANT_PATH_MATCHER.match(pattern, requestUri)) {
                        return true;
                    }
                }
            }
            return false;
        }

        public static String md5Sign(String... raws) {
            StringBuilder rawStr = new StringBuilder();
            for (String raw : raws) {
                rawStr.append(raw);
            }
            return Encrypt.md5(rawStr.toString().getBytes(StandardCharsets.UTF_8));
        }

        public static <K, V> String toQueryStr(Map<K, V> paramMap) {
            return toQueryStr(paramMap, false);
        }

        public static <K, V> String toQueryStr(Map<K, V> paramMap, boolean encode) {
            StringBuilder strBuilder = new StringBuilder();

            int paramIndex = 0;
            List<K> allKey = Coll.sort(paramMap.keySet());
            for (; paramIndex < allKey.size(); paramIndex++) {
                if (null == paramMap.get(allKey.get(paramIndex))) {
                    continue;
                }
                strBuilder.append(allKey.get(paramIndex));
                strBuilder.append("=");
                strBuilder.append(encode ? URLEncoder.encode(String.valueOf(paramMap.get(allKey.get(paramIndex))), StandardCharsets.UTF_8) : paramMap.get(allKey.get(paramIndex)));
                strBuilder.append("&");
            }
            strBuilder.deleteCharAt(strBuilder.lastIndexOf("&"));
            return strBuilder.toString();
        }

        public static String get(String uri) {
            Call call = CLIENT.newCall(new Request.Builder()
                    .url(uri)
                    .get()
                    .build());
            try (Response response = call.execute()) {
                ResponseBody body = response.body();
                return null == body ? Str.EMPTY : body.string();
            } catch (Exception e) {
                return Str.EMPTY;
            }
        }

        /**
         * Get string.
         *
         * @param uri     the uri
         * @param headers the headers
         * @return the string
         */
        public static String get(String uri, Map<String, String> headers) {
            Call call = CLIENT.newCall(new Request.Builder()
                    .url(uri)
                    .headers(Headers.of(headers))
                    .get()
                    .build());
            try (Response response = call.execute()) {
                ResponseBody body = response.body();
                return null == body ? Str.EMPTY : body.string();
            } catch (Exception e) {
                return Str.EMPTY;
            }
        }

        /**
         * Get string.
         *
         * @param uri   the uri
         * @param token the token
         * @return the string
         */
        public static String get(String uri, String token) {
            Call call = CLIENT.newCall(new Request.Builder()
                    .header(HEADER_AUTHORIZATION, token)
                    .url(uri)
                    .get()
                    .build());
            try (Response response = call.execute()) {
                ResponseBody body = response.body();
                return null == body ? Str.EMPTY : body.string();
            } catch (Exception e) {
                return Str.EMPTY;
            }
        }

        /**
         * Post string.
         *
         * @param uri the uri
         * @return the string
         */
        public static String post(String uri) {
            return post(uri, Str.EMPTY);
        }

        /**
         * Post for bytes byte [ ].
         *
         * @param uri         the uri
         * @param requestBody the request body
         * @return the byte [ ]
         */
        public static byte[] postForBytes(String uri, String requestBody) {
            Call call = CLIENT.newCall(new Request.Builder()
                    .url(uri)
                    .post(RequestBody.create(requestBody, MediaType.get(CONTENT_TYPE_JSON)))
                    .build());
            return executeForByte(call);
        }

        /**
         * Post string.
         *
         * @param uri         the uri
         * @param requestBody the request body
         * @return the string
         */
        public static String post(String uri, String requestBody) {
            Call call = CLIENT.newCall(new Request.Builder()
                    .url(uri)
                    .post(RequestBody.create(requestBody, MediaType.get(CONTENT_TYPE_JSON)))
                    .build());
            return executeForString(call);
        }

        /**
         * Post string.
         *
         * @param uri         the uri
         * @param requestBody the request body
         * @param headers     the headers
         * @return the string
         */
        public static String post(String uri, String requestBody, Map<String, String> headers) {
            Call call = CLIENT.newCall(new Request.Builder()
                    .url(uri)
                    .headers(Headers.of(headers))
                    .post(RequestBody.create(requestBody, MediaType.get(CONTENT_TYPE_JSON)))
                    .build());
            return executeForString(call);
        }

        /**
         * Post string.
         *
         * @param uri         the uri
         * @param requestBody the request body
         * @param token       the token
         * @return the string
         */
        public static String post(String uri, String requestBody, String token) {
            Call call = CLIENT.newCall(new Request.Builder()
                    .url(uri)
                    .header(HEADER_AUTHORIZATION, token)
                    .post(RequestBody.create(requestBody, MediaType.get(CONTENT_TYPE_JSON)))
                    .build());
            return executeForString(call);
        }

        /**
         * Post form string.
         *
         * @param uri         the uri
         * @param requestBody the request body
         * @return the string
         */
        public static String postForm(String uri, String requestBody) {
            Call call = CLIENT.newCall(new Request.Builder()
                    .url(uri)
                    .post(RequestBody.create(requestBody, MediaType.get(CONTENT_TYPE_FORM)))
                    .build());
            return executeForString(call);
        }

        /**
         * Post string.
         *
         * @param uri          the uri
         * @param requestParam the request param
         * @return the string
         */
        public static String post(String uri, Map<String, Object> requestParam) {
            FormBody.Builder builder = new FormBody.Builder();
            for (Map.Entry<String, Object> entry : requestParam.entrySet()) {
                if (null != entry.getValue()) {
                    builder.add(entry.getKey(), (String) entry.getValue());
                }
            }
            Call call = CLIENT.newCall(new Request.Builder()
                    .url(uri)
                    .post(builder.build())
                    .build());
            return executeForString(call);
        }

        /**
         * Delete string.
         *
         * @param url     the url
         * @param param   the param
         * @param headers the headers
         * @return the string
         */
        public static String delete(String url, String param, Map<String, String> headers) {
            return executeForString(CLIENT.newCall(new Request.Builder()
                    .url(url + QUERY_PARAM_CONNECT + param)
                    .headers(Headers.of(headers))
                    .delete()
                    .build()));
        }

        /**
         * Put string.
         *
         * @param uri         the uri
         * @param requestBody the request body
         * @param headers     the headers
         * @return the string
         */
        public static String put(String uri, String requestBody, Map<String, String> headers) {
            return executeForString(CLIENT.newCall(new Request.Builder()
                    .url(uri)
                    .headers(Headers.of(headers))
                    .put(RequestBody.create(requestBody, MediaType.get(CONTENT_TYPE_JSON)))
                    .build()));
        }

        /**
         * Websocket.
         *
         * @param url       the url
         * @param message   the message
         * @param onMessage the on message
         */
        public static void websocket(String url, String message, Consumer<String> onMessage) {
            CLIENT.newWebSocket(
                    new Request.Builder()
                            .url(url)
                            .build(),
                    new WebSocketListener() {
                        @Override
                        public void onClosed(@NotNull WebSocket webSocket, int code, @NotNull String reason) {
                            super.onClosed(webSocket, code, reason);
                        }

                        @Override
                        public void onClosing(@NotNull WebSocket webSocket, int code, @NotNull String reason) {
                            super.onClosing(webSocket, code, reason);
                        }

                        @Override
                        public void onFailure(@NotNull WebSocket webSocket, @NotNull Throwable t, @Nullable Response response) {
                            super.onFailure(webSocket, t, response);
                        }

                        @Override
                        public void onMessage(@NotNull WebSocket webSocket, @NotNull String text) {
                            super.onMessage(webSocket, text);
                            onMessage.accept(text);
                        }

                        @Override
                        public void onOpen(@NotNull WebSocket webSocket, @NotNull Response response) {
                            super.onOpen(webSocket, response);
                            webSocket.send(message);
                        }
                    }
            );
        }

        /**
         * Sse.
         *
         * @param url         the url
         * @param requestBody the request body
         * @param token       the token
         * @param onEvent     the on event
         */
        public static void sse(String url, String requestBody, String token, BiConsumer<String, String> onEvent) {
            Request.Builder requestBuilder = new Request.Builder()
                    .url(url)
                    .post(RequestBody.create(requestBody, MediaType.get(CONTENT_TYPE_JSON)))
                    .header("Accept", CONTENT_TYPE_EVENT_STREAM)
                    .header("Content-Type", CONTENT_TYPE_EVENT_STREAM);
            if (Str.isNotBlank(token)) {
                requestBuilder.header(HEADER_AUTHORIZATION, token);
            }

            RealEventSource eventSource = new RealEventSource(
                    requestBuilder.build(),
                    new EventSourceListener() {
                        @Override
                        public void onClosed(@NotNull EventSource eventSource) {
                            super.onClosed(eventSource);
                        }

                        @Override
                        public void onEvent(@NotNull EventSource eventSource, @Nullable String id, @Nullable String type, @NotNull String data) {
                            super.onEvent(eventSource, id, type, data);
                            onEvent.accept(type, data);
                        }

                        @Override
                        public void onFailure(@NotNull EventSource eventSource, @Nullable Throwable t, @Nullable Response response) {
                            super.onFailure(eventSource, t, response);
                        }
                    }
            );
            eventSource.connect(CLIENT);
        }

        public static MultiValueMap<String, String> getFormParameters(HttpServletRequest request) {
            Map<String, String[]> parameterMap = request.getParameterMap();
            MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
            parameterMap.forEach((key, values) -> {
                String queryString = StringUtils.hasText(request.getQueryString()) ? request.getQueryString() : "";
                // If not query parameter then it's a form parameter
                if (!queryString.contains(key) && Array.isNotBlank(values)) {
                    for (String value : values) {
                        parameters.add(key, value);
                    }
                }
            });
            return parameters;
        }

        public static MultiValueMap<String, String> getQueryParameters(HttpServletRequest request) {
            Map<String, String[]> parameterMap = request.getParameterMap();
            MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
            parameterMap.forEach((key, values) -> {
                String queryString = StringUtils.hasText(request.getQueryString()) ? request.getQueryString() : "";
                if (queryString.contains(key) && Array.isNotBlank(values)) {
                    for (String value : values) {
                        parameters.add(key, value);
                    }
                }
            });
            return parameters;
        }

        private static String executeForString(Call call) {
            try (Response execute = call.execute()) {
                return Objects.requireNonNull(execute.body()).string();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }

        private static byte[] executeForByte(Call call) {
            try (Response execute = call.execute()) {
                ResponseBody body = execute.body();
                return null == body ? new byte[0] : body.bytes();
            } catch (IOException e) {
                return new byte[0];
            }
        }
    }

    /**
     * The type Network.
     */
    @Slf4j
    public static class Network {

        private Network() {

        }

        private static final String UNKNOWN = "unknown";

        private static Searcher IP_SEARCHER = null;

        private static final UserAgentAnalyzer USER_AGENT_PARSER = UserAgentAnalyzer
                .newBuilder()
                .hideMatcherLoadStats()
                .withCache(10000)
                .build();

        static {
            String dbPath;
            String osName = System.getProperty("os.name").toLowerCase();
            if (osName.contains("windows")) {
                String userProfile = System.getenv("USERPROFILE");
                dbPath = userProfile + "\\.iking\\ip2region.xdb";
            } else {
                dbPath = "/opt/iking/ip2region.xdb";
            }
            try {
                IP_SEARCHER = Searcher.newWithBuffer(Searcher.loadContentFromFile(dbPath));
            } catch (Exception e) {
                log.error("failed to load content from `{}`: {}", dbPath, e.getMessage());
            }
        }

        /**
         * Ip string.
         *
         * @param request the request
         * @return the string
         */
        public static String ip(HttpServletRequest request) {
            String ip = request.getHeader("x-forwarded-for");
            if (Str.isNotBlank(ip) && ip.contains(Str.COMMA)) {
                ip = ip.split(Str.COMMA)[0];
            }
            if (ip != null && !ip.isEmpty() && !UNKNOWN.equalsIgnoreCase(ip)) {
                return ip;
            }
            ip = request.getHeader("Proxy-Client-IP");
            if (ip != null && !ip.isEmpty() && !UNKNOWN.equalsIgnoreCase(ip)) {
                return ip;
            }
            ip = request.getHeader("WL-Proxy-Client-IP");
            if (ip != null && !ip.isEmpty() && !UNKNOWN.equalsIgnoreCase(ip)) {
                return ip;
            }
            ip = request.getHeader("HTTP_CLIENT_IP");
            if (ip != null && !ip.isEmpty() && !UNKNOWN.equalsIgnoreCase(ip)) {
                return ip;
            }
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
            if (ip != null && !ip.isEmpty() && !UNKNOWN.equalsIgnoreCase(ip)) {
                return ip;
            }
            ip = request.getHeader("X-Real-IP");
            if (ip != null && !ip.isEmpty() && !UNKNOWN.equalsIgnoreCase(ip)) {
                return ip;
            }
            return request.getRemoteAddr();
        }

        /**
         * Ip region string.
         *
         * @param ip the ip
         * @return the string
         */
        public static String ipRegion(String ip) {
            String ipRegion = "未知";
            if (null != IP_SEARCHER) {
                try {
                    ipRegion = IP_SEARCHER.search(ip);
                } catch (Exception e) {
                    log.error("[N/A]failed to search({}): {}", ip, e.getMessage());
                }
            }

            return Coll.join(Coll.filter(Coll.distinct(Str.split(ipRegion, "|")), str -> !str.matches("\\d")), ".");
        }

        public static UserAgentInfo userAgent(String userAgent) {
            UserAgent.ImmutableUserAgent parseResult = USER_AGENT_PARSER.parse(userAgent);
            UserAgentInfo userAgentInfo = new UserAgentInfo();
            userAgentInfo.setOperatingSystem(parseResult.getValue("OperatingSystemNameVersionMajor"));
            userAgentInfo.setBrowser(parseResult.getValue("AgentNameVersionMajor"));
            return userAgentInfo;
        }

        @Data
        public static class UserAgentInfo implements Serializable {

            @Serial
            private static final long serialVersionUID = 8280110295674269360L;

            private String operatingSystem;

            private String browser;
        }
    }

    /**
     * The type Id.
     */
    public static class Id {

        private Id() {

        }

        /**
         * Uuid string.
         *
         * @return the string
         */
        public static String uuid() {
            final Random ng = ThreadLocalRandom.current();

            final byte[] randomBytes = new byte[16];
            ng.nextBytes(randomBytes);

            randomBytes[6] &= 0x0f; /* clear version */
            randomBytes[6] |= 0x40; /* set to version 4 */
            randomBytes[8] &= 0x3f; /* clear variant */
            randomBytes[8] |= (byte) 0x80; /* set to IETF variant */


            long msb = 0;
            long lsb = 0;
            for (int i = 0; i < 8; i++) {
                msb = (msb << 8) | (randomBytes[i] & 0xff);
            }
            for (int i = 8; i < 16; i++) {
                lsb = (lsb << 8) | (randomBytes[i] & 0xff);
            }

            return create(msb, lsb);
        }

        private static String create(long msb, long lsb) {
            final StringBuilder builder = new StringBuilder(32);

            // time_low
            long hi = 1L << (8 * 4);
            builder.append(Long.toHexString(hi | (msb >> 32 & (hi - 1))).substring(1));
            // time_mid
            hi = 1L << (4 * 4);
            builder.append(Long.toHexString(hi | (msb >> 16 & (hi - 1))).substring(1));
            // time_high_and_version
            builder.append(Long.toHexString(hi | (msb & (hi - 1))).substring(1));
            // variant_and_sequence
            builder.append(Long.toHexString(hi | (lsb >> 48 & (hi - 1))).substring(1));
            // node
            hi = 1L << (4 * 12);
            builder.append(Long.toHexString(hi | (lsb & (hi - 1))).substring(1));
            return builder.toString();
        }
    }

    /**
     * The type Cron.
     */
    public static class Cron {

        private Cron() {

        }

        /**
         * 返回该corn表达式指定的时间的下一个周期执行时间
         *
         * @param cronStr cron表达式
         * @return 下一个执行时间 local date time
         */
        public static LocalDateTime next(String cronStr) {
            CronExpression expression = CronExpression.parse(cronStr);
            return expression.next(LocalDateTime.now());
        }
    }

    /**
     * The type Byte stream.
     */
    public static class ByteStream {

        private ByteStream() {
            // do nothing
        }

        /**
         * Read all string.
         *
         * @param in the in
         * @return the string
         */
        public static String readAll(InputStream in) {
            try {
                byte[] bytes = new byte[in.available()];
                int readBytesLength = in.read(bytes);
                if (readBytesLength != bytes.length) {
                    return Str.EMPTY;
                }

                return new String(bytes, StandardCharsets.UTF_8);
            } catch (IOException e) {
                return Str.EMPTY;
            }
        }
    }

    /**
     * The type Obj.
     */
    public static class Obj {

        private Obj() {
            // do nothing
        }

        /**
         * String string.
         *
         * @param obj the obj
         * @return the string
         */
        public static String string(Object obj) {
            if (obj instanceof String) {
                return String.valueOf(obj);
            }
            return Str.EMPTY;
        }

        public static List<String> list(Object obj) {
            List<String> result = new ArrayList<>();
            if (obj instanceof List<?> tempList) {
                for (Object o : tempList) {
                    // 进行类型转换，添加到 list 中
                    result.add(String.valueOf(o));
                }
            }
            return result;
        }

        public static <T> List<T> list(Object obj, Class<T> clazz) {
            List<T> result = new ArrayList<>();
            if (obj instanceof List<?> tempList) {
                for (Object o : tempList) {
                    // 进行类型转换，添加到 list 中
                    result.add(clazz.cast(o));
                }
            }
            return result;
        }

        public static List<Object> objList(Object obj) {
            List<Object> result = new ArrayList<>();
            if (obj instanceof List<?> tempList) {
                // 进行类型转换，添加到 list 中
                result.addAll(tempList);
            }
            return result;
        }
    }

    /**
     * The type Date time.
     */
    @NoArgsConstructor(access = AccessLevel.PRIVATE)
    public static class DateTime {

        /**
         * The constant UTC_DATETIME_PATTERN.
         */
        public static final String UTC_DATETIME_PATTERN = "yyyy-MM-dd'T'HH:mm:ss'Z'";

        /**
         * The constant SIMPLE_DATETIME_PATTERN.
         */
        public static final String SIMPLE_DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss";

        /**
         * The constant SIMPLE_DATE_PATTERN.
         */
        public static final String SIMPLE_DATE_PATTERN = "yyyy-MM-dd";

        /**
         * The constant PURE_DATETIME_PATTERN.
         */
        public static final String PURE_DATETIME_PATTERN = "yyyyMMddHHmmss";

        /**
         * The constant PURE_MS_DATETIME_PATTERN.
         */
        public static final String PURE_MS_DATETIME_PATTERN = "yyyyMMddHHmmssSSS";

        /**
         * The constant ZONE_CHINA.
         */
        public static final String ZONE_CHINA = "GMT+8";

        /**
         * The constant ZONE_UTC.
         */
        public static final String ZONE_UTC = "UTC";

        /**
         * Simple date time formatter date time formatter.
         *
         * @return the date time formatter
         */
        public static DateTimeFormatter simpleDateTimeFormatter() {
            return DateTimeFormatter.ofPattern(SIMPLE_DATETIME_PATTERN);
        }

        /**
         * Simple date formatter date time formatter.
         *
         * @return the date time formatter
         */
        public static DateTimeFormatter simpleDateFormatter() {
            return DateTimeFormatter.ofPattern(SIMPLE_DATE_PATTERN);
        }

        /**
         * Pure date time formatter date time formatter.
         *
         * @return the date time formatter
         */
        public static DateTimeFormatter pureDateTimeFormatter() {
            return DateTimeFormatter.ofPattern(PURE_DATETIME_PATTERN);
        }

        /**
         * Pure ms date time formatter date time formatter.
         *
         * @return the date time formatter
         */
        public static DateTimeFormatter pureMsDateTimeFormatter() {
            return DateTimeFormatter.ofPattern(PURE_MS_DATETIME_PATTERN);
        }

        /**
         * The type Formatter.
         */
        @NoArgsConstructor(access = AccessLevel.PRIVATE)
        public static class Formatter {

            /**
             * Simple string.
             *
             * @return the string
             */
            public static String simple() {
                return simple(LocalDateTime.now());
            }

            /**
             * Simple string.
             *
             * @param time the time
             * @return the string
             */
            public static String simple(@Nullable LocalDateTime time) {
                if (null == time) {
                    return Str.EMPTY;
                }
                return time.format(simpleDateTimeFormatter().withZone(ZoneId.of(ZONE_CHINA)));
            }

            /**
             * Simple date string.
             *
             * @return the string
             */
            public static String simpleDate() {
                return simpleDate(LocalDate.now());
            }

            /**
             * Simple date string.
             *
             * @param time the time
             * @return the string
             */
            public static String simpleDate(@Nullable LocalDate time) {
                if (null == time) {
                    return Str.EMPTY;
                }
                return time.format(simpleDateFormatter().withZone(ZoneId.of(ZONE_CHINA)));
            }

            /**
             * Pure string.
             *
             * @return the string
             */
            public static String pure() {
                return pure(LocalDateTime.now());
            }

            /**
             * Pure string.
             *
             * @param time the time
             * @return the string
             */
            public static String pure(LocalDateTime time) {
                return time.format(pureDateTimeFormatter().withZone(ZoneId.of(ZONE_CHINA)));
            }

            /**
             * Pure ms string.
             *
             * @return the string
             */
            public static String pureMs() {
                return pureMs(LocalDateTime.now());
            }

            /**
             * Pure ms string.
             *
             * @param time the time
             * @return the string
             */
            public static String pureMs(LocalDateTime time) {
                return time.format(pureMsDateTimeFormatter().withZone(ZoneId.of(ZONE_CHINA)));
            }

            /**
             * Utc string.
             *
             * @return the string
             */
            public static String utc() {
                return utc(LocalDateTime.now());
            }

            /**
             * Utc string.
             *
             * @param time the time
             * @return the string
             */
            public static String utc(LocalDateTime time) {
                return time.format(DateTimeFormatter.ofPattern(UTC_DATETIME_PATTERN).withZone(ZoneId.of(ZONE_UTC)));
            }
        }

        /**
         * The type Parser.
         */
        @NoArgsConstructor(access = AccessLevel.PRIVATE)
        public static class Parser {
            /**
             * Pure local date time.
             *
             * @param timeStr the time str
             * @return the local date time
             */
            public static LocalDateTime pure(String timeStr) {
                return LocalDateTime.parse(timeStr, pureDateTimeFormatter());
            }

            /**
             * Simple local date time.
             *
             * @param timeStr the time str
             * @return the local date time
             */
            public static LocalDateTime simple(String timeStr) {
                return LocalDateTime.parse(timeStr, simpleDateTimeFormatter());
            }
        }

        /**
         * Duration string.
         *
         * @param start the start
         * @param end   the end
         * @return the string
         */
        public static String duration(LocalDateTime start, LocalDateTime end) {
            return duration(start, end, Str.EMPTY);
        }

        /**
         * Duration string.
         *
         * @param start            the start
         * @param end              the end
         * @param recentMappedText the recent mapped text
         * @return the string
         */
        public static String duration(LocalDateTime start, LocalDateTime end, String recentMappedText) {
            Duration waitTimeBetween = Duration.between(start, end);

            long waitDays = waitTimeBetween.toSeconds() / 86400; // 获取天数
            long waitHours = (0L == waitDays ? waitTimeBetween.toSeconds() : waitTimeBetween.toSeconds() % 86400) / 3600; // 获取小时数
            long waitMinutes = (0L == waitHours ? waitTimeBetween.toSeconds() : waitTimeBetween.toSeconds() % 3600) / 60; // 获取剩余的分钟数
            if (0L != waitDays) {
                return Str.format("{}天{}小时{}分钟", waitDays, waitHours, waitMinutes);
            } else {
                if (0L != waitHours) {
                    return Str.format("{}小时{}分钟", waitHours, waitMinutes);
                } else {
                    if (0 != waitMinutes) {
                        return Str.format("{}分钟", waitMinutes);
                    } else {
                        return Str.isNotBlank(recentMappedText) ? recentMappedText : Str.format("{}秒", waitTimeBetween.toSeconds());
                    }
                }
            }
        }
    }

    /**
     * MD5加密工具类
     *
     * @author DPJ
     * @since 2023 -05-24
     */
    @Slf4j
    @NoArgsConstructor(access = AccessLevel.PRIVATE)
    public static class Encrypt {

        /**
         * byte 数组MD5加密
         *
         * @param bytes 要加密的byte数组
         * @return 加密结果 string
         */
        public static String md5(byte[] bytes) {
            if (bytes == null || bytes.length == 0) {
                return Str.EMPTY;
            }
            String s;
            char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
            try {
                MessageDigest md = MessageDigest.getInstance("MD5");
                md.update(bytes);
                byte[] tmp = md.digest();
                char[] str = new char[16 * 2];
                int k = 0;
                for (int i = 0; i < 16; i++) {
                    byte byte0 = tmp[i];
                    str[k++] = hexDigits[byte0 >>> 4 & 0xf];
                    str[k++] = hexDigits[byte0 & 0xf];
                }
                s = new String(str);
            } catch (NoSuchAlgorithmException e) {
                return Str.EMPTY;
            }
            return s;
        }

        /**
         * Rsa string.
         *
         * @param rawStr        the raw str
         * @param privateKeyStr the private key str
         * @return the string
         */
        public static String rsa(String rawStr, String privateKeyStr) {
            Signature privateSignature;
            try {
                privateSignature = Signature.getInstance("SHA1WithRSA");
            } catch (NoSuchAlgorithmException e) {
                return Str.EMPTY;
            }
            byte[] byteKey = Base64.getDecoder().decode(privateKeyStr.getBytes());
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(byteKey);
            KeyFactory keyFactory;
            try {
                keyFactory = KeyFactory.getInstance("RSA");
            } catch (NoSuchAlgorithmException e) {
                log.error("get RSA key factory instance fail[{}]", e.getMessage());
                return Str.EMPTY;
            }
            PrivateKey privateKey;
            try {
                privateKey = keyFactory.generatePrivate(keySpec);
            } catch (InvalidKeySpecException e) {
                log.error("generate private key fail[{}]", e.getMessage());
                return Str.EMPTY;
            }
            try {
                privateSignature.initSign(privateKey);
            } catch (InvalidKeyException e) {
                log.error("init signature by privateKey fail[{}]", e.getMessage());
                return Str.EMPTY;
            }
            try {
                privateSignature.update(rawStr.getBytes(StandardCharsets.UTF_8));
            } catch (SignatureException e) {
                log.error("update signature by plain text fail[{}]", e.getMessage());
                return Str.EMPTY;
            }

            byte[] signature;
            try {
                signature = privateSignature.sign();
            } catch (SignatureException e) {
                log.error("calculate sign fail[{}]", e.getMessage());
                return Str.EMPTY;
            }

            return Base64.getEncoder().encodeToString(signature);
        }

        /**
         * Sha 256 string.
         *
         * @param rawStr the raw str
         * @param secret the secret
         * @return the string
         */
        public static String sha256(String rawStr, String secret) {
            Mac mac;
            try {
                mac = Mac.getInstance("hmacsha256");
            } catch (NoSuchAlgorithmException e) {
                return Str.EMPTY;
            }
            SecretKeySpec sp = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "hmacsha256");
            try {
                mac.init(sp);
            } catch (InvalidKeyException e) {
                return Str.EMPTY;
            }
            return Base64.getEncoder().encodeToString(mac.doFinal(rawStr.getBytes(StandardCharsets.UTF_8)));
        }

        /**
         * Aes string.
         *
         * @param raw the raw
         * @param key the key
         * @return the string
         */
        public static String aes(String raw, String key) {
            String encryptStr;
            try {
                SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "AES");
                Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
                cipher.init(Cipher.ENCRYPT_MODE, keySpec);
                byte[] encryptData = cipher.doFinal(raw.getBytes(StandardCharsets.UTF_8));
                encryptStr = new String(Base64.getEncoder().encode(encryptData), StandardCharsets.UTF_8);
            } catch (Exception e) {
                return Str.EMPTY;
            }
            return encryptStr;
        }
    }

    /**
     * The type Decrypt.
     */
    @NoArgsConstructor(access = AccessLevel.PRIVATE)
    public static class Decrypt {

        private Cipher cipher;

        /**
         * Instance decrypt.
         *
         * @param algorithm the algorithm
         * @return the decrypt
         */
        public static Decrypt instance(String algorithm) {
            Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
            Decrypt decrypt = new Decrypt();
            try {
                decrypt.cipher = Cipher.getInstance(algorithm);
                return decrypt;
            } catch (Exception e) {
                throw new CipherInstanceException("algorithm is " + algorithm);
            }
        }

        /**
         * Aes string.
         *
         * @param encryptedStr the encrypted str
         * @param secretKey    the secret key
         * @param iv           the iv
         * @return the string
         */
        public String aes(String encryptedStr, String secretKey, String iv) {
            try {
                cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), "AES"), new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8)));
            } catch (Exception e) {
                return Str.EMPTY;
            }
            try {
                return new String(cipher.doFinal(Base64.getDecoder().decode(encryptedStr)), Charset.defaultCharset());
            } catch (Exception e) {
                return Str.EMPTY;
            }
        }

        /**
         * The type Cipher instance exception.
         */
        public static class CipherInstanceException extends RuntimeException {

            @Serial
            private static final long serialVersionUID = 7425594520832055885L;

            /**
             * Instantiates a new Cipher instance exception.
             *
             * @param message the message
             */
            public CipherInstanceException(String message) {
                super(message);
            }
        }
    }

    /**
     * The type Velocity.
     */
    public static class Velocity {

        private final VelocityContext context = new VelocityContext();

        static {
            // 设置velocity资源加载器
            Properties prop = new Properties();
            prop.put("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
            org.apache.velocity.app.Velocity.init(prop);
        }

        /**
         * Instance velocity.
         *
         * @return the velocity
         */
        public static Velocity instance() {
            Velocity velocity = new Velocity();
            // 函数库
            velocity.context.put("math", new MathTool());
            velocity.context.put("dateTool", new DateTool());
            return velocity;
        }

        /**
         * Context velocity.
         *
         * @param variable the variable
         * @param data     the data
         * @return the velocity
         */
        public Velocity context(String variable, Object data) {
            this.context.put(variable, data);
            return this;
        }

        /**
         * Generate string.
         *
         * @param template the template
         * @return the string
         */
        public String generate(String template) {
            StringWriter content = new StringWriter();
            org.apache.velocity.app.Velocity.getTemplate(template, StandardCharsets.UTF_8.name()).merge(this.context, content);
            return content.toString();
        }
    }

    /**
     * The type Zip.
     */
    @Slf4j
    public static class Zip {

        private final Map<String, String> entryDataMap = new HashMap<>();

        /**
         * Instance zip.
         *
         * @return the zip
         */
        public static Zip instance() {
            return new Zip();
        }

        /**
         * Entry zip.
         *
         * @param fileName the file name
         * @param content  the content
         * @return the zip
         */
        public Zip entry(String fileName, String content) {
            this.entryDataMap.put(fileName, content);
            return this;
        }

        /**
         * Write.
         *
         * @param outputStream the output stream
         */
        public void write(OutputStream outputStream) {
            try (ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream)) {
                this.entryDataMap.forEach((fileName, data) -> {
                    try {
                        zipOutputStream.putNextEntry(new ZipEntry(fileName));
                    } catch (IOException e) {
                        log.error("生成ZIP压缩包Entry失败[{}]", e.getMessage());
                        return;
                    }

                    try {
                        zipOutputStream.write(data.getBytes(Charset.defaultCharset()));
                    } catch (IOException e) {
                        log.error("写入ZIP失败[{}]", e.getMessage());
                        return;
                    }

                    try {
                        zipOutputStream.flush();
                    } catch (IOException e) {
                        log.error("ZIP Flush失败[{}]", e.getMessage());
                    }
                });
            } catch (IOException e) {
                log.error("创建ZipOutputStream失败[{}]", e.getMessage());
            }
        }
    }

    public static class Reg {

        public static boolean weakPassword(String password) {
            return !password.matches("^(?=.*[A-Z])(?=.*[a-z])(?=.*\\d)(?=.*[+-.!@#$%^&*?]).{6,}$");
        }

        public static boolean invalidUsername(String username) {
            return !username.matches("^(?!.*(?:select|from|where|group|order|by|insert|into|update|set|delete|alert))(?=.*[a-z0-9_\\u4e00-\\u9fa5])[a-z0-9_\\u4e00-\\u9fa5]{1,64}$");
        }
    }

    public static class Csv {

        private static String CSV_FILE_PATH = null;

        static {
            String dbPath;
            String osName = System.getProperty("os.name").toLowerCase();
            if (osName.contains("windows")) {
                String userProfile = System.getenv("USERPROFILE");
                CSV_FILE_PATH = userProfile + "\\.iking\\ip2region.xdb";
            } else {
                CSV_FILE_PATH = "/opt/iking/ip2region.xdb";
            }
        }

        public static void readByLine(String filePath, Consumer<String> processLine) {
            try (BufferedReader br = new BufferedReader(new FileReader(filePath))) {
                String csvLine;
                while ((csvLine = br.readLine()) != null) {
                    // 处理每一行数据
                    processLine.accept(csvLine);
                }
            } catch (IOException e) {
                System.err.println("Error reading CSV file: " + e.getMessage());
            }
        }
    }
}
